#ifndef __SECTION_CPP__
#define __SECTION_CPP__

#include "env.h"
#include "output.h"
#include "section.h"

namespace WServer {

namespace GData {
Section::wserSection* gOption;
}

namespace Section {
wserSection::wserSection()
{
	root = new struct wserSectionNode;
	root->prefix = root->key = root->value = "";
	root->parent = root->sibling = root->child = NULL;
	memset(memdata, 0, MAX_SIZE);
	remain = curpos = filesize = 0;
	bend = true;
}

wserSection::wserSection(std::string filename)
{
	root = new struct wserSectionNode;
	root->prefix = root->key = root->value = "";
	root->parent = root->sibling = root->child = NULL;
	memset(memdata, 0, MAX_SIZE);
	remain = curpos = filesize = 0;
	bend = true;
	this->OpenFile(filename);
}

wserSection::~wserSection()
{
	DeleteNode(root);
}

void wserSection::DeleteNode(wserSectionNode* node)
{
	if (node) {
		if (node->child) DeleteNode(node->child);
		if (node->sibling) DeleteNode(node->sibling);
		node->child = node->sibling = node->parent = NULL;
		delete node;
		node = NULL;
	}
}

int wserSection::OpenFile(std::string filename)
{
	int hfile = open(filename.c_str(), O_RDONLY);
	if (hfile == -1) return -1;
	filesize = lseek(hfile, 0, SEEK_END);
	lseek(hfile, 0, SEEK_SET);
	bend = false;
	if (ReadKeylist(hfile) == -1) return -1;
	if (ReadSections(hfile) == -1) return -1;
	close(hfile);
	return 0;
}

int wserSection::ReadData(int hfile, void* data, int len)
{
	if (curpos+len > remain) {
		//short of data, read from file.
		char chread[MAX_SIZE];
		int size;
		memset(chread, 0, MAX_SIZE);
		//copy the remain data to chread first.
		memcpy(chread, memdata+curpos, remain-curpos);
		memset(memdata, 0, MAX_SIZE);
		//then read from file.
		size = read(hfile, chread+remain-curpos, HALF_SIZE);
		//finally copy chread to memdata, overwrite.
		remain = remain-curpos+size;
		curpos = 0;
		memcpy(memdata, chread, remain);
	}
	memcpy(data, memdata+curpos, len);
	curpos += len;
	if (lseek(hfile, 0, SEEK_CUR) == filesize && remain <= curpos) bend = true;
}

int wserSection::ReadKeylist(int hfile)
{
	int count = 0, len, i;
	char* name;
	ReadData(hfile, &count, sizeof(int));
	for (i = 0;i < count;i++) {
		ReadData(hfile, &len, sizeof(int));
		name = new char[len+1];
		memset(name, 0, len+1);
		ReadData(hfile, name, len);
		keylist.push_back(name);
		if (name) {
			delete[] name;
			name = NULL;
		}
	}
	return 0;
}

int wserSection::ReadSections(int hfile)
{
	char flag, scount;
	int ccount, len, i;
	std::string prefix, key, value;
	char* ch = NULL;
	while (!bend) {
		ReadData(hfile, &flag, 1);
		prefix = key = value = "";
		ReadData(hfile, &scount, 1);
		for (i = 0;i < scount;i++) {
			ReadData(hfile, &ccount, sizeof(int));
			if (i == scount-1) {
				key = keylist[ccount];
			}
			else {
				prefix += "|"+keylist[ccount];
			}
		}
		if (flag == 2) {
			ReadData(hfile, &ccount, sizeof(int));
			ch = new char[ccount+1];
			memset(ch, 0, ccount+1);
			ReadData(hfile, ch, ccount);
			value = ch;
			if (ch) {
				delete[] ch;
				ch = NULL;
			}
		}
		else {
			key += "|";
		}
		NewNode(prefix, key, value);
	}
}

struct wserSectionNode* wserSection::MatchSection(struct wserSectionNode* recursive, std::string name)
{
	std::string fullname;
	int f, l;
	struct wserSectionNode* node;
	struct wserSectionNode* child;
	if (recursive->prefix == "" && recursive->key == "") {
		if (name == "") {
			//recursive is root and name is blank.
			return recursive;
		}
	}
	else {
		fullname = recursive->prefix+"|"+recursive->key;
		f = fullname.find_first_not_of("|");
		l = fullname.find_last_not_of("|");
		fullname = fullname.substr(f, l-f+1);
		f = name.find_first_not_of("|");
		l = name.find_last_not_of("|");
		name = name.substr(f, l-f+1);
		if (name == fullname)
			//recursive's fullname matches the prefix.
			return recursive;
	}
	if (recursive->child) {
		child = recursive->child;
		do {
			node = MatchSection(child, name);
			if (node) {
				return node;
			}
			child = child->sibling;
			if (!child) break;
		} while (1);
	}
	return NULL;
}

struct wserSectionNode* wserSection::GetSibling(struct wserSectionNode* parent)
{
	struct wserSectionNode* p = parent->child;
	if (p) {
		while (p->sibling) p = p->sibling;
	}
	return p;
}

struct wserSectionNode* wserSection::NewNode(std::string prefix, std::string key, std::string value)
{
	struct wserSectionNode* node = new struct wserSectionNode;
	node->prefix = prefix;
	node->key = key;
	node->value = value;
	struct wserSectionNode* p;
	node->parent = MatchSection(root, prefix);
	node->sibling = NULL;
	p = GetSibling(node->parent);
	if (p) {
		p->sibling = node;
	}
	else {
		node->parent->child = node;
	}
	node->child = NULL;
	return node;
}

std::string wserSection::GetString(std::string key)
{
	struct wserSectionNode* p = MatchSection(root, key);
	if (p) return p->value;
	return "";
}

int wserSection::GetInteger(std::string key)
{
	struct wserSectionNode* p = MatchSection(root, key);
	if (p) return atoi(p->value.c_str());
	return 0;
}

struct wserSectionNode* wserSection::GetSubNode(std::string key)
{
	return MatchSection(root, key);
}

struct wserSectionNode* wserSection::GetFirstNode()
{
	if (keylist.size() > 0) {
		return MatchSection(root, keylist[0]);
	}
	return NULL;
}
}
}
#endif //__SECTION_CPP__
